/**
 * 从Excel对象中提取数组，兼容横向和纵向选择的单元格区域
 * @param row_or_col
 * @returns {*}
 */
function array_from_region(row_or_col) {
  let xArray
  if (row_or_col.hasOwnProperty('Value2')) {
    if (Array.isArray(row_or_col.Value2[0]) && row_or_col.Value2.length > 1) {
      // 处理 [Array(1), Array(1)] 这种情况
      xArray = row_or_col.Value2.map(x => x[0])
    } else {
      // 处理 [Array(3)] 这种情况
      xArray = row_or_col.Value2[0]
    }
  }
  return xArray
}

/**
 * 归一化数组，将array归一化，使其和为1，用于处理天然气组分，使得各组分百分比之和为1
 * @param arr
 * @private
 */
function _normalize_array(arr) {
  const sum = arr.reduce((acc, val) => acc + val, 0)
  if (sum !== 0) {
    for (let i = 0; i < arr.length; i++) {
      arr[i] = arr[i] / sum
    }
  }
  return arr
}

function 燃气摩尔密度(压力, 温度, 压缩因子) {
  if (温度 > 273.15) {
    温度 = 温度 - 273.15
  }
  return 压力 / 压缩因子 / 0.00831451 / (温度 + 273.15)
}

function 摩尔质量_湿空气(干空气分数) {
  // 干空气摩尔分数，为常数
  let frac_mole_N2_dry = 0.78084
  let frac_mole_O2_dry = 0.2094760
  let frac_mole_CO2_dry = 0.0003190
  let frac_mole_Ar_dry = 0.009365

  // 湿空气摩尔分数
  let frac_mole_N2_wet = frac_mole_N2_dry * 干空气分数
  let frac_mole_O2_wet = frac_mole_O2_dry * 干空气分数
  let frac_mole_CO2_wet = frac_mole_CO2_dry * 干空气分数
  let frac_mole_H2O_wet = 1 - 干空气分数
  let frac_mole_Ar_wet = frac_mole_Ar_dry * 干空气分数

  // 摩尔质量
  let mass_mole_N2 = 28.0135
  let mass_mole_O2 = 31.9988
  let mass_mole_CO2 = 44.01
  let mass_mole_H2O = 18.0153
  let mass_mole_Ar = 39.948

  let N2 = frac_mole_N2_wet * mass_mole_N2
  let O2 = frac_mole_O2_wet * mass_mole_O2
  let CO2 = frac_mole_CO2_wet * mass_mole_CO2
  let H2O = frac_mole_H2O_wet * mass_mole_H2O
  let Ar = frac_mole_Ar_wet * mass_mole_Ar

  return N2 + O2 + CO2 + H2O + Ar
}

function 摩尔质量_燃气(组分体积分数数组_百分比) {
  let p_compo = 组分体积分数数组_百分比.Value2
  let p_compo_arr = []

  for (let i = 0; i < p_compo.length; i++) {
    p_compo_arr[i] = p_compo[i][0] / 100
  }

  let M_mole = [16.043, 28.0135, 44.01, 30.07, 44.097, 18.0153, 34.082, 2.0159, 28.01, 31.9988,
    58.123, 58.123, 72.15, 72.15, 86.177, 100.204, 114.231, 128.258, 142.285, 4.0026, 39.948]

  let sum = 0
  for (let i = 0; i < p_compo_arr.length; i++) {
    sum = sum + M_mole[i] * p_compo_arr[i]
  }
  return sum
}

/**
 * 计算燃气质量低位发热量（参比温度为15℃）
 * @param 组分体积分数数组_百分比 - 各组分体积分数数组（百分比）
 * @returns 燃气质量低位发热量 (kJ/kg)
 */
function LHV_gas(组分体积分数数组_百分比) {
  const XI = [0, ...array_from_region(组分体积分数数组_百分比)]

  // 各组分的摩尔质量 (kg/kmol)
  const M_mole = [0, 16.043, 28.0135, 44.01, 30.07, 44.097, 18.0153, 34.082, 2.0159, 28.01, 31.9988,
    58.123, 58.123, 72.15, 72.15, 86.177, 100.204, 114.231, 128.258, 142.285, 4.0026, 39.948]

  // 各组分的摩尔低位发热量 (MJ/kmol)
  const M_heat = [0, 50.035, 0, 0, 47.52, 46.34, 0, 15.2, 119.91, 10.1, 0, 45.57, 45.72, 45.25, 45.35,
    45.11, 44.93, 44.79, 44.69, 44.6, 0, 0]

  // 计算各组分的质量分数
  const M_xi = new Array(22).fill(0)
  let m = 0 // 混合物的摩尔质量

  for (let i = 1; i <= 21; i++) {
    M_xi[i] = XI[i] * M_mole[i]
    m = m + M_xi[i]
  }

  // 计算各组分的质量分数
  const mass_frac = new Array(22).fill(0)
  for (let i = 1; i <= 21; i++) {
    mass_frac[i] = M_xi[i] / m
  }

  // 计算质量低位发热量
  let LHV_gas_T15 = 0
  for (let i = 1; i <= 21; i++) {
    LHV_gas_T15 = LHV_gas_T15 + mass_frac[i] * M_heat[i]
  }

  // 转换为 kJ/kg
  return LHV_gas_T15 * 1000
}

/**
 * 计算燃气中碳氢元素质量比
 * @param 组分体积分数数组_百分比 - 各组分体积分数数组（百分比）
 * @returns number
 */
function 碳氢比_质量(组分体积分数数组_百分比) {
  // 处理输入数据，将百分比转换为小数
  const XI = [0, ..._normalize_array(array_from_region(组分体积分数数组_百分比))]

  // 计算碳原子质量 (按照VBA中的公式)
  const C_mass = (XI[1] + XI[4] * 2 + XI[5] * 3 + XI[9] * 1 + XI[11] * 4 + XI[12] * 4
    + XI[13] * 5 + XI[14] * 5 + XI[15] * 6 + XI[16] * 7 + XI[17] * 8 + XI[18] * 9 + XI[19] * 10) * 12

  // 计算氢原子质量 (按照VBA中的公式)
  const H_mass = XI[1] * 4 + XI[4] * 6 + XI[5] * 8 + XI[6] * 2 + XI[7] * 2 + XI[8] * 2 + XI[11] * 10 + XI[12] * 10
    + XI[13] * 12 + XI[14] * 12 + XI[15] * 14 + XI[16] * 16 + XI[17] * 18 + XI[18] * 20 + XI[19] * 22

  // 返回碳氢质量比
  return C_mass / H_mass
}

function 摩尔流量变化(组分名, 燃气摩尔流量, 组分体积分数数组) {
  // 燃烧产物相对于进口空气摩尔流量的组分摩尔流量变化
  // 组分名可取值："CO2","O2","N2","Ar","H2O","SO2"
  // 组分体积分数数组的组分顺序为：甲烷、氮气、二氧化碳、乙烷、丙烷、水、硫化氢、氢气、一氧化碳、氧气
  // 异丁烷、正丁烷、异戊烷、正戊烷、己烷、庚烷、辛烷、壬烷、癸烷、氦气、氩气
  const p_compo_arr = _normalize_array(array_from_region(组分体积分数数组))

  if (p_compo_arr.length !== 21) {
    return '组分不全'
  }
  let change = []
  if (组分名 === 'O2') {
    change = [-2, 0, 0, -3.5, -5, 0, -1.5, -0.5, -0.5, 1, -6.5, -6.5, -8, -8, -9.5, -11, -12.5, -14, -15.5, 0, 0]
  }
  if (组分名 === 'N2') {
    return p_compo_arr[1] * 燃气摩尔流量
  } else if (组分名 === 'CO2') {
    change = [1, 0, 1, 2, 3, 0, 0, 0, 1, 0, 4, 4, 5, 5, 6, 7, 8, 9, 10, 0, 0]
  } else if (组分名 === 'H2O') {
    change = [2, 0, 0, 3, 4, 1, 1, 1, 0, 0, 5, 5, 6, 6, 7, 8, 9, 10, 11, 0, 0]
  } else if (组分名 === 'Ar') {
    return 0
  } else if (组分名 === 'SO2') {
    return 0
  }

  let sum = 0
  for (let i = 0; i < p_compo_arr.length; i++) {
    sum = sum + p_compo_arr[i] * change[i]
  }
  return sum * 燃气摩尔流量
}

function 燃烧所需干空气质量流量(燃气摩尔流量, 组分体积分数数组) {
  // 组分体积分数数组即燃料气的组分报告，体积分数=摩尔分数
  //
  if (燃气摩尔流量 === undefined) {
    alert('请输入正确的燃气摩尔流量')
    return '请输入正确的燃气摩尔流量'
  }
  let 燃气燃烧所需氧气的摩尔流量 = -摩尔流量变化('O2', 燃气摩尔流量, 组分体积分数数组)
  let 燃气燃烧所需干空气的摩尔流量 = 燃气燃烧所需氧气的摩尔流量 / 0.209476
  // 此处干空气的分子量与余热锅炉规程不同
  return 燃气燃烧所需干空气的摩尔流量 * 28.965194
}

function 燃烧所需湿空气质量流量(空气含湿量_1, 燃气摩尔流量, 组分体积分数数组) {
  let 干空气质量流量 = 燃烧所需干空气质量流量(燃气摩尔流量, 组分体积分数数组)
  return 干空气质量流量 * (1 + 空气含湿量_1)
}

function 燃烧产物摩尔流量(组分名, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt) {
  // 组分名：N2, O2, CO2, H2O, Ar, SO2
  // 干空气分数：即燃机所处环境空气的干空气分数，为体积分数或摩尔分数
  // 燃烧所需湿空气质量流量，kg/h

  if (注入流量_opt === undefined || 注入流量_opt + 0 !== 注入流量_opt) {
    注入流量_opt = 0
  }

  let mass_mole_gas = 摩尔质量_燃气(燃气组分体积分数数组)
  let flow_mole_gas = 燃料质量流量 / mass_mole_gas

  // 湿空气摩尔分数
  let frac_mole_N2_wet = 摩尔分数_湿空气('N2', 干空气分数)
  let frac_mole_O2_wet = 摩尔分数_湿空气('O2', 干空气分数)
  let frac_mole_CO2_wet = 摩尔分数_湿空气('CO2', 干空气分数)
  let frac_mole_H2O_wet = 摩尔分数_湿空气('H2O', 干空气分数)
  let frac_mole_Ar_wet = 摩尔分数_湿空气('Ar', 干空气分数)

  // 摩尔质量
  // let mass_mole_N2 = 28.0135
  // let mass_mole_O2 = 31.9988
  // let mass_mole_CO2 = 44.01
  // let mass_mole_H2O = 18.0153
  // let mass_mole_Ar = 39.948
  let mass_mole_humid_air = 摩尔质量_湿空气(干空气分数)

  // 湿空气摩尔流量
  let flow_mole_humid_air = 燃烧所需湿空气质量流量 / mass_mole_humid_air
  let flow_mole_N2 = flow_mole_humid_air * frac_mole_N2_wet
  let flow_mole_O2 = flow_mole_humid_air * frac_mole_O2_wet
  let flow_mole_CO2 = flow_mole_humid_air * frac_mole_CO2_wet
  let flow_mole_H2O = flow_mole_humid_air * frac_mole_H2O_wet
  let flow_mole_Ar = flow_mole_humid_air * frac_mole_Ar_wet

  // 燃烧摩尔变化
  let delta_N2 = 摩尔流量变化('N2', flow_mole_gas, 燃气组分体积分数数组)
  let delta_O2 = 摩尔流量变化('O2', flow_mole_gas, 燃气组分体积分数数组)
  let delta_CO2 = 摩尔流量变化('CO2', flow_mole_gas, 燃气组分体积分数数组)
  let delta_H2O = 摩尔流量变化('H2O', flow_mole_gas, 燃气组分体积分数数组)
  let delta_Ar = 摩尔流量变化('Ar', flow_mole_gas, 燃气组分体积分数数组)
  let delta_SO2 = 摩尔流量变化('SO2', flow_mole_gas, 燃气组分体积分数数组)

  // 燃机排气摩尔流量
  let flow_mole_N2_to = flow_mole_N2 + delta_N2
  let flow_mole_O2_to = flow_mole_O2 + delta_O2
  let flow_mole_CO2_to = flow_mole_CO2 + delta_CO2
  let flow_mole_H2O_to = flow_mole_H2O + delta_H2O + 注入流量_opt / 18.0153
  let flow_mole_Ar_to = flow_mole_Ar + delta_Ar
  // 燃机排汽质量分数
  if (组分名 === 'N2') {
    return flow_mole_N2_to
  } else if (组分名 === 'O2') {
    return flow_mole_O2_to
  } else if (组分名 === 'CO2') {
    return flow_mole_CO2_to
  } else if (组分名 === 'H2O') {
    return flow_mole_H2O_to
  } else if (组分名 === 'SO2') {
    return delta_SO2
  } else if (组分名 === 'Ar') {
    return flow_mole_Ar_to
  } else {
    return '未知组分名'
  }
}


function 燃烧产物质量分数(组分名, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt) {
  // 组分名：N2, O2, CO2, H2O, Ar, SO2
  // 干空气分数：即燃机所处环境空气的干空气分数，为体积分数或摩尔分数
  // 燃烧所需湿空气质量流量，kg/h

  if (注入流量_opt === undefined || 注入流量_opt + 0 !== 注入流量_opt) {
    注入流量_opt = 0
  }

  // 燃机排气摩尔流量
  let flow_mole_N2_to = 燃烧产物摩尔流量('N2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_O2_to = 燃烧产物摩尔流量('O2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_CO2_to = 燃烧产物摩尔流量('CO2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_H2O_to = 燃烧产物摩尔流量('H2O', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_Ar_to = 燃烧产物摩尔流量('Ar', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_SO2_to = 燃烧产物摩尔流量('SO2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)

  let mass_flow_total = 燃烧所需湿空气质量流量 + 燃料质量流量 + 注入流量_opt

  // 燃机排汽质量分数
  if (组分名 === 'N2') {
    return flow_mole_N2_to * 28.0135 / mass_flow_total
  } else if (组分名 === 'O2') {
    return flow_mole_O2_to * 31.9988 / mass_flow_total
  } else if (组分名 === 'CO2') {
    return flow_mole_CO2_to * 44.01 / mass_flow_total
  } else if (组分名 === 'H2O') {
    return flow_mole_H2O_to * 18.0153 / mass_flow_total
  } else if (组分名 === 'SO2') {
    return flow_mole_SO2_to * 64.0638 / mass_flow_total
  } else if (组分名 === 'Ar') {
    return flow_mole_Ar_to * 39.948 / mass_flow_total
  } else {
    return '未知组分名'
  }
}

function 焓_组分(组分名, 温度_K, 基准温度_K) {
  if (基准温度_K === undefined || 基准温度_K + 0 !== 基准温度_K) { // 如果由另一个函数调用，则基准温度_K可能为空的number类型，则满足第二个条件
    基准温度_K = 288.15
  }
  let R = 8.31451
  let F = new Array(11)
  if (组分名 === 'N2') {
    F[1] = 22103.715
    F[2] = -381.84618
    F[3] = 6.08273836
    F[4] = -0.008530914
    F[5] = 0.0000138465
    F[6] = -0.00000000962579
    F[7] = 2.51971E-12
    F[8] = 710.846086
    F[9] = 0
    F[10] = 28.0134
  } else if (组分名 === 'O2') {
    F[1] = -34255.6342
    F[2] = 484.700097
    F[3] = 1.11901096
    F[4] = 0.004293889
    F[5] = -0.00000068363
    F[6] = -0.00000000202337
    F[7] = 1.03904E-12
    F[8] = -3391.4549
    F[9] = 0
    F[10] = 31.9988
  } else if (组分名 === 'CO2') {
    F[1] = 49436.5054
    F[2] = -626.411601
    F[3] = 5.30172524
    F[4] = 0.002503814
    F[5] = -0.00000021273
    F[6] = -0.000000000768999
    F[7] = 2.84968E-13
    F[8] = -45281.9846
    F[9] = -393510
    F[10] = 44.0095
  } else if (组分名 === 'H2O') {
    F[1] = -39479.6083
    F[2] = 575.573102
    F[3] = 0.931782653
    F[4] = 0.007222713
    F[5] = -0.00000734256
    F[6] = 0.00000000495504
    F[7] = -1.33693E-12
    F[8] = -33039.7431
    F[9] = -241826
    F[10] = 18.0153
  } else if (组分名 === 'Ar') {
    F[1] = 0
    F[2] = 0
    F[3] = 2.5
    F[4] = 0
    F[5] = 0
    F[6] = 0
    F[7] = 0
    F[8] = -745.375
    F[9] = 0
    F[10] = 39.948
  } else if (组分名 === 'SO2') {
    F[1] = -53108.4214
    F[2] = 909.031167
    F[3] = -2.356891244
    F[4] = 0.0220445
    F[5] = -0.0000251078
    F[6] = 0.000000014463
    F[7] = -3.36907E-12
    F[8] = -41137.5212
    F[9] = -296810
    F[10] = 64.0638
  } else if (组分名 === 'CO') {
    F[1] = 14890.45326
    F[2] = -292.2285939
    F[3] = 5.72452717
    F[4] = -0.008176235
    F[5] = 0.000014569
    F[6] = -0.0000000108775
    F[7] = 3.02794E-12
    F[8] = -13031.31878
    F[9] = -110535.196
    F[10] = 28.0101
  } else if (组分名 === 'H2S') {
    F[1] = 9543.80881
    F[2] = -68.7517508
    F[3] = 4.05492196
    F[4] = -0.000301456
    F[5] = 0.0000037685
    F[6] = -0.00000000223936
    F[7] = 3.08686E-13
    F[8] = -3278.45728
    F[9] = -20600
    F[10] = 34.0809
  } else if (组分名 === 'H2') {
    F[1] = 40783.2321
    F[2] = -800.918604
    F[3] = 8.21470201
    F[4] = -0.012697145
    F[5] = 0.0000175361
    F[6] = -0.0000000120286
    F[7] = 3.36809E-12
    F[8] = 2682.484665
    F[9] = 0
    F[10] = 2.0159
  } else if (组分名 === 'He') {
    F[1] = 0
    F[2] = 0
    F[3] = 2.5
    F[4] = 0
    F[5] = 0
    F[6] = 0
    F[7] = 0
    F[8] = 745.375
    F[9] = 0
    F[10] = 4.0026
  } else if (组分名 === 'CH4') {
    F[1] = -176685.0998
    F[2] = 2786.18102
    F[3] = -12.0257785
    F[4] = 0.039176193
    F[5] = -0.0000361905
    F[6] = 0.0000000202685
    F[7] = -4.97671E-12
    F[8] = -23313.1436
    F[9] = -74600
    F[10] = 16.0425
  } else if (组分名 === 'C2H6') {
    F[1] = -186204.4161
    F[2] = 3406.19186
    F[3] = -19.51705092
    F[4] = 0.075658356
    F[5] = -0.0000820417
    F[6] = 0.0000000506114
    F[7] = -1.31928E-11
    F[8] = -27029.3289
    F[9] = -83851.544
    F[10] = 30.069
  } else if (组分名 === 'C3H8') {
    F[1] = -243314.4337
    F[2] = 4656.27081
    F[3] = -29.39466091
    F[4] = 0.118895275
    F[5] = -0.000137631
    F[6] = 0.0000000881482
    F[7] = -2.34299E-11
    F[8] = -35403.3527
    F[9] = -104680
    F[10] = 44.0956
  } else if (组分名 === 'C4H10iso') {
    F[1] = -383446.933
    F[2] = 7000.03964
    F[3] = -44.400269
    F[4] = 0.174618345
    F[5] = -0.00020782
    F[6] = 0.000000133979
    F[7] = -3.55168E-11
    F[8] = -50340.1889
    F[9] = -134990
    F[10] = 58.1222
  } else if (组分名 === 'C4H10n') {
    F[1] = -317587.254
    F[2] = 6176.33182
    F[3] = -38.9156212
    F[4] = 0.158465428
    F[5] = -0.000186005
    F[6] = 0.000000119968
    F[7] = -3.20167E-11
    F[8] = -45403.6339
    F[9] = -125790
    F[10] = 58.1222
  } else if (组分名 === 'C5H12iso') {
    F[1] = -423190.339
    F[2] = 6497.1891
    F[3] = -36.8112697
    F[4] = 0.153242473
    F[5] = -0.000154879
    F[6] = 0.000000087499
    F[7] = -2.07055E-11
    F[8] = -51554.1659
    F[9] = -153700
    F[10] = 72.1488
  } else if (组分名 === 'C5H12n') {
    F[1] = -276889.4625
    F[2] = 5834.28347
    F[3] = -36.1754148
    F[4] = 0.153333971
    F[5] = -0.00015284
    F[6] = 0.0000000819109
    F[7] = -1.79233E-11
    F[8] = -46653.7525
    F[9] = -146760
    F[10] = 72.1488
  } else if (组分名 === 'C6H14n') {
    F[1] = -581592.67
    F[2] = 10790.97724
    F[3] = -66.3394703
    F[4] = 0.252371516
    F[5] = -0.000290434
    F[6] = 0.00000018022
    F[7] = -4.61722E-11
    F[8] = -72715.4457
    F[9] = -166920
    F[10] = 86.1754
  }

  let H = ((-F[1] / 温度_K + F[2] * Math.log(温度_K) + F[3] * 温度_K + F[4] * 温度_K * 温度_K / 2 + F[5] * Math.pow(温度_K, 3) / 3
    + F[6] * Math.pow(温度_K, 4) / 4 + F[7] * Math.pow(温度_K, 5) / 5 + F[8]) * R - F[9]) / F[10] / 2.326
  let Hr = ((-F[1] / 基准温度_K + F[2] * Math.log(基准温度_K) + F[3] * 基准温度_K + F[4] * 基准温度_K * 基准温度_K / 2
    + F[5] * Math.pow(基准温度_K, 3) / 3
    + F[6] * Math.pow(基准温度_K, 4) / 4 + F[7] * Math.pow(基准温度_K, 5) / 5 + F[8]) * R - F[9]) / F[10] / 2.326
  return 2.326 * (H - Hr)
}

/**
 * 计算燃气显热
 * @param T_C - 温度（℃）
 * @param T0_C - 基准温度（℃）
 * @param 组分体积分数数组_百分比 - 各组分体积分数数组（百分比）
 * @returns 燃气显热
 */
function 焓_燃气(T_C, T0_C, 组分体积分数数组_百分比) {
  // 处理输入数据，将百分比转换为小数
  const p_compo = 组分体积分数数组_百分比.Value2
  const XI = new Array(22).fill(0) // 创建22个元素的数组并初始化为0

  // 按照VBA代码逻辑处理输入数据，从索引1开始填充
  for (let i = 0; i < p_compo.length; i++) {
    XI[i + 1] = p_compo[i][0] / 100
  }

  // 各组分的摩尔质量 (kg/kmol)
  const M_mole = [0, 16.043, 28.0135, 44.01, 30.07, 44.097, 18.0153, 34.082, 2.0159, 28.01, 31.9988,
    58.123, 58.123, 72.15, 72.15, 86.177, 100.204, 114.231, 128.258, 142.285, 4.0026, 39.948]

  // 各组分的焓值
  const h_xi = new Array(22).fill(0)
  h_xi[1] = 焓_组分('CH4', T_C + 273.15, T0_C + 273.15)
  h_xi[2] = 焓_组分('N2', T_C + 273.15, T0_C + 273.15)
  h_xi[3] = 焓_组分('CO2', T_C + 273.15, T0_C + 273.15)
  h_xi[4] = 焓_组分('C2H6', T_C + 273.15, T0_C + 273.15)
  h_xi[5] = 焓_组分('C3H8', T_C + 273.15, T0_C + 273.15)
  h_xi[6] = 焓_组分('H2O', T_C + 273.15, T0_C + 273.15)
  h_xi[7] = 焓_组分('H2S', T_C + 273.15, T0_C + 273.15)
  h_xi[8] = 焓_组分('H2', T_C + 273.15, T0_C + 273.15)
  h_xi[9] = 焓_组分('CO', T_C + 273.15, T0_C + 273.15)
  h_xi[10] = 焓_组分('O2', T_C + 273.15, T0_C + 273.15)
  h_xi[11] = 焓_组分('C4H10iso', T_C + 273.15, T0_C + 273.15)
  h_xi[12] = 焓_组分('C4H10n', T_C + 273.15, T0_C + 273.15)
  h_xi[13] = 焓_组分('C5H12iso', T_C + 273.15, T0_C + 273.15)
  h_xi[14] = 焓_组分('C5H12n', T_C + 273.15, T0_C + 273.15)
  h_xi[15] = 焓_组分('C6H14n', T_C + 273.15, T0_C + 273.15)
  h_xi[16] = 焓_组分('C6H14n', T_C + 273.15, T0_C + 273.15)
  h_xi[17] = 焓_组分('C6H14n', T_C + 273.15, T0_C + 273.15)
  h_xi[18] = 焓_组分('C6H14n', T_C + 273.15, T0_C + 273.15)
  h_xi[19] = 焓_组分('C6H14n', T_C + 273.15, T0_C + 273.15)
  h_xi[20] = 焓_组分('Ar', T_C + 273.15, T0_C + 273.15)
  h_xi[21] = 焓_组分('Ar', T_C + 273.15, T0_C + 273.15)

  // 计算总质量
  let Mass_all = 0
  for (let I = 1; I <= 21; I++) {
    Mass_all = Mass_all + XI[I] * M_mole[I]
  }

  // 计算各组分的质量分数
  const M_mass_gas = new Array(22).fill(0)
  for (let I = 1; I <= 21; I++) {
    M_mass_gas[I] = XI[I] * M_mole[I] / Mass_all
  }

  // 计算燃气显热
  let H_gas_xianre_result = 0
  for (let I = 1; I <= 21; I++) {
    H_gas_xianre_result = H_gas_xianre_result + M_mass_gas[I] * h_xi[I]
  }

  return H_gas_xianre_result
}

function 焓_燃烧产物_余热锅炉进出口(进口或出口温度, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt, 基准温度_opt) {
  // 此处的燃烧产物不考虑平衡湿空气
  // 余热锅炉进口即燃机排气
  let 基准温度_K = 基准温度_opt + 273.15
  let 温度_K = 进口或出口温度 + 273.15

  // 获取烟气中各种组分的质量分数
  let mass_frac_N2 = 燃烧产物质量分数('N2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let mass_frac_O2 = 燃烧产物质量分数('O2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let mass_frac_CO2 = 燃烧产物质量分数('CO2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let mass_frac_H2O = 燃烧产物质量分数('H2O', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let mass_frac_SO2 = 燃烧产物质量分数('SO2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let mass_frac_Ar = 燃烧产物质量分数('Ar', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)

  // 获取烟气中各种组分的焓
  let h_N2 = 焓_组分('N2', 温度_K, 基准温度_K)
  let h_O2 = 焓_组分('O2', 温度_K, 基准温度_K)
  let h_CO2 = 焓_组分('CO2', 温度_K, 基准温度_K)
  let h_H2O = 焓_组分('H2O', 温度_K, 基准温度_K)
  let h_SO2 = 焓_组分('SO2', 温度_K, 基准温度_K)
  let h_Ar = 焓_组分('Ar', 温度_K, 基准温度_K)

  return mass_frac_N2 * h_N2 + mass_frac_O2 * h_O2 + mass_frac_CO2 * h_CO2 + mass_frac_H2O * h_H2O
    + mass_frac_SO2 * h_SO2 + mass_frac_Ar * h_Ar
}

function 摩尔分数_湿空气(组分名, 干空气分数) {
  // 干空气摩尔分数，为常数
  let frac_mole_N2_dry = 0.78084
  let frac_mole_O2_dry = 0.2094760
  let frac_mole_CO2_dry = 0.0003190
  let frac_mole_H2O_dry = 0
  let frac_mole_Ar_dry = 0.009365
  // 湿空气摩尔分数
  if (组分名 === 'N2') {
    return frac_mole_N2_dry * 干空气分数
  } else if (组分名 === 'O2') {
    return frac_mole_O2_dry * 干空气分数
  } else if (组分名 === 'CO2') {
    return frac_mole_CO2_dry * 干空气分数
  } else if (组分名 === 'H2O') {
    return 1 - 干空气分数
  } else if (组分名 === 'Ar') {
    return frac_mole_Ar_dry * 干空气分数
  } else if (组分名 === 'SO2') {
    return 0
  } else {
    return 0
  }
}

function 平衡空气流量_HRSG(HRSG进口平衡空气焓, HRSG出口平衡空气焓, HRSG进口燃烧产物焓, HRSG出口燃烧产物焓, 燃烧产物质量流量, HRSG热负荷) {
  /**
   * HRSG平衡空气即燃机进口空气扣除燃烧必须的空气后富余的空气
   * HRSG燃烧产物即燃气和其燃烧必须的空气燃烧后的产物，不包括平衡空气量
   * HRSG热负荷即余热锅炉传递给汽水循环中的总热量
   */
  let 分子 = HRSG热负荷 + (0.0015 - 1) * 燃烧产物质量流量 * HRSG进口燃烧产物焓 + 燃烧产物质量流量 * HRSG出口燃烧产物焓
  let 分母 = (1 - 0.0015) * HRSG进口平衡空气焓 - HRSG出口平衡空气焓
  return 分子 / 分母
}

function 平衡湿空气流量_燃机(燃气质量流量_kg_h, 燃气LHV_kJ_kg, 燃气显热, 燃烧所需湿空气流量, 燃机进口湿空气焓, 燃机出口湿空气焓, 燃烧产物焓, 发电机功率_kW, 燃机总损失_kW) {
    let 进口能量 = 燃气质量流量_kg_h * (燃气LHV_kJ_kg + 燃气显热) + 燃烧所需湿空气流量 * 燃机进口湿空气焓;  // kJ/h
    let 发电当量能量 = (发电机功率_kW + 燃机总损失_kW) * 3600 // kJ/h
    let 出口能量 = (燃气质量流量_kg_h + 燃烧所需湿空气流量) * 燃烧产物焓 + 发电当量能量 // kJ/h
    return (进口能量 - 出口能量) / (燃机出口湿空气焓 - 燃机进口湿空气焓)
}


function 燃机排气质量分数(组分名, 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt) {
  if (注入流量_opt === undefined || 注入流量_opt + 0 !== 注入流量_opt) {
    注入流量_opt = 0
  }

  // 燃烧产物摩尔流量
  let flow_mole_N2_to = 燃烧产物摩尔流量('N2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_O2_to = 燃烧产物摩尔流量('O2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_CO2_to = 燃烧产物摩尔流量('CO2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_H2O_to = 燃烧产物摩尔流量('H2O', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_Ar_to = 燃烧产物摩尔流量('Ar', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let flow_mole_SO2_to = 燃烧产物摩尔流量('SO2', 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)

  let mass_mole_humid_air = 摩尔质量_湿空气(干空气分数)
  let flow_mole_humid_air = 平衡空气质量流量 / mass_mole_humid_air
  let flow_mass_all = 平衡空气质量流量 + 燃料质量流量 + 燃烧所需湿空气质量流量 + 注入流量_opt

  // 湿空气摩尔分数
  let frac_mole_N2_wet = 摩尔分数_湿空气('N2', 干空气分数)
  let frac_mole_O2_wet = 摩尔分数_湿空气('O2', 干空气分数)
  let frac_mole_CO2_wet = 摩尔分数_湿空气('CO2', 干空气分数)
  let frac_mole_H2O_wet = 摩尔分数_湿空气('H2O', 干空气分数)
  let frac_mole_Ar_wet = 摩尔分数_湿空气('Ar', 干空气分数)

  // 平衡空气摩尔流量
  let flow_mole_N2_wa = flow_mole_humid_air * frac_mole_N2_wet
  let flow_mole_O2_wa = flow_mole_humid_air * frac_mole_O2_wet
  let flow_mole_CO2_wa = flow_mole_humid_air * frac_mole_CO2_wet
  let flow_mole_H2O_wa = flow_mole_humid_air * frac_mole_H2O_wet
  let flow_mole_Ar_wa = flow_mole_humid_air * frac_mole_Ar_wet

  // 燃机排汽摩尔流量
  let flow_mole_N2 = flow_mole_N2_wa + flow_mole_N2_to
  let flow_mole_O2 = flow_mole_O2_wa + flow_mole_O2_to
  let flow_mole_CO2 = flow_mole_CO2_wa + flow_mole_CO2_to
  let flow_mole_H2O = flow_mole_H2O_wa + flow_mole_H2O_to
  let flow_mole_Ar = flow_mole_Ar_wa + flow_mole_Ar_to
  // 燃机排气质量分数
  if (组分名 === 'N2') {
    return 28.0135 * flow_mole_N2 / flow_mass_all
  } else if (组分名 === 'O2') {
    return 31.9988 * flow_mole_O2 / flow_mass_all
  } else if (组分名 === 'CO2') {
    return 44.01 * flow_mole_CO2 / flow_mass_all
  } else if (组分名 === 'H2O') {
    return 18.0153 * flow_mole_H2O / flow_mass_all
  } else if (组分名 === 'Ar') {
    return 39.948 * flow_mole_Ar / flow_mass_all
  } else if (组分名 === 'SO2') {
    return 64.0638 * flow_mole_SO2_to / flow_mass_all
  }
}

function 焓_烟气(烟气温度, 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt, 基准温度_opt) {
  // 考虑平衡湿空气时余热锅炉各处的烟气焓
  if (注入流量_opt === undefined || 注入流量_opt + 0 !== 注入流量_opt) {
    注入流量_opt = 0
  }
  if (基准温度_opt === undefined || 基准温度_opt + 0 !== 基准温度_opt) {
    基准温度_opt = 15
  }
  let frac_mass_N2 = 燃机排气质量分数('N2', 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let frac_mass_O2 = 燃机排气质量分数('O2', 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let frac_mass_CO2 = 燃机排气质量分数('CO2', 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let frac_mass_H2O = 燃机排气质量分数('H2O', 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let frac_mass_Ar = 燃机排气质量分数('Ar', 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
  let frac_mass_SO2 = 燃机排气质量分数('SO2', 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)

  // 组分焓
  let h_N2 = 焓_组分('N2', 烟气温度 + 273.15, 基准温度_opt + 273.15)
  let h_O2 = 焓_组分('O2', 烟气温度 + 273.15, 基准温度_opt + 273.15)
  let h_CO2 = 焓_组分('CO2', 烟气温度 + 273.15, 基准温度_opt + 273.15)
  let h_H2O = 焓_组分('H2O', 烟气温度 + 273.15, 基准温度_opt + 273.15)
  let h_Ar = 焓_组分('Ar', 烟气温度 + 273.15, 基准温度_opt + 273.15)
  let h_SO2 = 焓_组分('SO2', 烟气温度 + 273.15, 基准温度_opt + 273.15)

  return frac_mass_N2 * h_N2 + frac_mass_O2 * h_O2 + frac_mass_CO2 * h_CO2 + frac_mass_H2O * h_H2O + frac_mass_Ar * h_Ar + frac_mass_SO2 * h_SO2
}

function 质量分数_湿空气(组分名, 干空气分数) {
  // 湿空气摩尔分数
  let frac_mole_N2_wet = 摩尔分数_湿空气('N2', 干空气分数)
  let frac_mole_O2_wet = 摩尔分数_湿空气('O2', 干空气分数)
  let frac_mole_CO2_wet = 摩尔分数_湿空气('CO2', 干空气分数)
  let frac_mole_H2O_wet = 摩尔分数_湿空气('H2O', 干空气分数)
  let frac_mole_Ar_wet = 摩尔分数_湿空气('Ar', 干空气分数)

  let mass_N2 = frac_mole_N2_wet * 28.0135
  let mass_O2 = frac_mole_O2_wet * 31.9988
  let mass_CO2 = frac_mole_CO2_wet * 44.01
  let mass_H2O = frac_mole_H2O_wet * 18.0153
  let mass_Ar = frac_mole_Ar_wet * 39.948
  let mass = mass_N2 + mass_O2 + mass_CO2 + mass_H2O + mass_Ar

  if (组分名 === 'N2') {
    return mass_N2 / mass
  } else if (组分名 === 'O2') {
    return mass_O2 / mass
  } else if (组分名 === 'CO2') {
    return mass_CO2 / mass
  } else if (组分名 === 'H2O') {
    return mass_H2O / mass
  } else if (组分名 === 'Ar') {
    return mass_Ar / mass
  } else if (组分名 === 'SO2') {
    return 0
  }
}

function 焓_湿空气(空气温度, 干空气分数, 基准温度_opt) {
  if (基准温度_opt === undefined || 基准温度_opt + 0 !== 基准温度_opt) {
    基准温度_opt = 15
  }
  // 组分焓
  let h_N2 = 焓_组分('N2', 空气温度 + 273.15, 基准温度_opt + 273.15)
  let h_O2 = 焓_组分('O2', 空气温度 + 273.15, 基准温度_opt + 273.15)
  let h_CO2 = 焓_组分('CO2', 空气温度 + 273.15, 基准温度_opt + 273.15)
  let h_H2O = 焓_组分('H2O', 空气温度 + 273.15, 基准温度_opt + 273.15)
  let h_Ar = 焓_组分('Ar', 空气温度 + 273.15, 基准温度_opt + 273.15)

  // 质量分数
  let frac_mass_N2 = 质量分数_湿空气('N2', 干空气分数)
  let frac_mass_O2 = 质量分数_湿空气('O2', 干空气分数)
  let frac_mass_CO2 = 质量分数_湿空气('CO2', 干空气分数)
  let frac_mass_H2O = 质量分数_湿空气('H2O', 干空气分数)
  let frac_mass_Ar = 质量分数_湿空气('Ar', 干空气分数)

  return frac_mass_N2 * h_N2 + frac_mass_O2 * h_O2 + frac_mass_CO2 * h_CO2 + frac_mass_H2O * h_H2O + frac_mass_Ar * h_Ar
}

function 压缩因子(压力, 温度, 组分体积分数数组) {
  // 定义迭代变量：n,i,j
  // NN:天然气组分数，NN=21
  let NN = 22
  if (温度 < 230) {
    温度 = 温度 + 273.15
  }
  // 定义气体常数，R=0.00831451 MJ/(kmol*K)
  R = 0.00831451

  // 将输入区域给天然气摩尔组分数组赋值
  let p_compo = 组分体积分数数组.Value2
  let p_compo_arr = []
  if (p_compo[0][0] > 1) {
    for (let i = 0; i < p_compo.length; i++) {
      p_compo_arr[i] = p_compo[i][0] / 100
    }
  }
  if (p_compo_arr.length !== 21) {
    return '组分不全'
  }

  // *****************************************************************************************************************
  let a = [0, 0.1538326, 1.341953, -2.998583, -0.04831228, 0.3757965, -1.589575, -0.05358847, 0.88659463, -0.71023704, -1.471722, 1.32185035, -0.78665925,
    0.00000000229129, 0.1576724, -0.4363864, -0.04408159, -0.003433888, 0.03205905, 0.02487355, 0.07332279, -0.001600573, 0.6424706, -0.4162601,
    -0.06689957, 0.2791795, -0.6966051, -0.002860589, -0.008098836, 3.150547, 0.007224479, -0.7057529, 0.5349792, -0.07931491, -1.418465, -5.99905E-17,
    0.1058402, 0.03431729, -0.007022847, 0.02495587, 0.04296818, 0.7465453, -0.2919613, 7.294616, -9.936757, -0.005399808, -0.2432567, 0.04987016,
    0.003733797, 1.874951, 0.002168144, -0.6587164, 0.000205518, 0.009776195, -0.02048708, 0.01557322, 0.006862415, -0.001226752, 0.002850908]
  let B = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
    5, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9]
  let C = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1,
    1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1]
  let K = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 4, 4, 0, 0, 2, 2, 2, 4, 4, 4, 4, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 0, 0, 2, 2, 2, 4, 4, 0, 2, 2,
    4, 4, 0, 2, 0, 2, 1, 2, 2, 2, 2]
  let U = [0, 0, 0.5, 1, 3.5, -0.5, 4.5, 0.5, 7.5, 9.5, 6, 12, 12.5, -6, 2, 3, 2, 2, 11, -0.5, 0.5, 0, 4, 6, 21, 23, 22, -1, -0.5, 7, -1, 6, 4, 1, 9, -13,
    21, 8, -0.5, 0, 2, 7, 9, 22, 23, 1, 9, 3, 8, 23, 1.5, 5, -0.5, 4, 7, 3, 0, 1, 0]
  let G = [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0]
  let Q = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
    0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1]
  let F = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  let S = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  let W = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  let MW = [0, 16.043, 28.0135, 44.01, 30.07, 44.097, 18.0153, 34.082, 2.0159, 28.01, 31.9988, 58.123, 58.123, 72.15, 72.15, 86.177, 100.204, 114.231,
    128.258, 142.285, 4.0026, 39.948]
  let EI = [0, 151.3183, 99.73778, 241.9606, 244.1667, 298.1183, 514.0156, 296.355, 26.95794, 105.5348, 122.7667, 324.0689, 337.6389, 365.5999, 370.6823,
    402.636293, 427.72263, 450.325022, 470.840891, 489.558373, 2.610111, 119.6299]
  let KI = [0, 0.4619255, 0.4479153, 0.4557489, 0.5279209, 0.583749, 0.3825868, 0.4618263, 0.3514916, 0.4533894, 0.4186954, 0.6406937, 0.6341423, 0.6738577,
    0.6798307, 0.7175118, 0.7525189, 0.784955, 0.8152731, 0.8437826, 0.3589888, 0.4216551]
  let GI = [0, 0, 0.027815, 0.189065, 0.0793, 0.141239, 0.3325, 0.0885, 0.034369, 0.038953, 0.021, 0.256692, 0.281835, 0.332267, 0.366911, 0.289731, 0.337542,
    0.383381, 0.427354, 0.469659, 0, 0]
  let QI = [0, 0, 0, 0.69, 0, 0, 1.06775, 0.633276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  let FI = [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  let SI = [0, 0, 0, 0, 0, 0, 1.5822, 0.39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  let WI = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  // 给EIJ赋初值
  let EIJ = [[1, 0.97164, 0.960644, 1, 0.994635, 0.708218, 0.931484, 1.17052, 0.990126, 1, 1.01953, 0.989844, 1.00235, 0.999268, 1.107274, 0.88088, 0.880973, 0.881067, 0.881161, 1, 1],
    [0.97164, 1, 1.02274, 0.97012, 0.945939, 0.746954, 0.902271, 1.08632, 1.00571, 1.021, 0.946914, 0.973384, 0.95934, 0.94552, 1, 1, 1, 1, 1, 1, 1],
    [0.960644, 1.02274, 1, 0.925053, 0.960237, 0.849408, 0.955052, 1.28179, 1.5, 1, 0.906849, 0.897362, 0.726255, 0.859764, 0.855134, 0.831229, 0.80831, 0.786323, 0.765171, 1, 1],
    [1, 0.97012, 0.925053, 1, 1.02256, 0.693168, 0.946871, 1.16446, 1, 1, 1, 1.01306, 1, 1.00532, 1, 1, 1, 1, 1, 1, 1],
    [0.994635, 0.945939, 0.960237, 1.02256, 1, 1, 1, 1.034787, 1, 1, 1, 1.0049, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.708218, 0.746954, 0.849408, 0.693168, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.931484, 0.902271, 0.955052, 0.946871, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.008692, 1.010126, 1.011501, 1.012821, 1.014089, 1, 1],
    [1.17052, 1.08632, 1.28179, 1.16446, 1.034787, 1, 1, 1, 1.1, 1, 1.3, 1.3, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.990126, 1.00571, 1.5, 1, 1, 1, 1, 1.1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1.021, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.01953, 0.946914, 0.906849, 1, 1, 1, 1, 1.3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.989844, 0.973384, 0.897362, 1.01306, 1.0049, 1, 1, 1.3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.00235, 0.95934, 0.726255, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.999268, 0.94552, 0.859764, 1.00532, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.107274, 1, 0.855134, 1, 1, 1, 1.008692, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.88088, 1, 0.831229, 1, 1, 1, 1.010126, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.880973, 1, 0.80831, 1, 1, 1, 1.011501, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.881067, 1, 0.786323, 1, 1, 1, 1.012821, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.881161, 1, 0.765171, 1, 1, 1, 1.014089, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

  EIJ = transpose(EIJ)
  // 给UIJ赋初值
  let UIJ = [[1, 0.886106, 0.963827, 1, 0.990877, 1, 0.736833, 1.15639, 1, 1, 1, 0.992291, 1, 1.00367, 1.302576, 1.191904, 1.205769, 1.219634, 1.233498, 1, 1],
    [0.886106, 1, 0.835058, 0.816431, 0.915502, 1, 0.993476, 0.408838, 1, 1, 1, 0.993556, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.963827, 0.835058, 1, 0.96987, 1, 1, 1.04529, 1, 0.9, 1, 1, 1, 1, 1, 1.066638, 1.077634, 1.088178, 1.098291, 1.108021, 1, 1],
    [1, 0.816431, 0.96987, 1, 1.065173, 1, 0.971926, 1.61666, 1, 1, 1.25, 1.25, 1.25, 1.25, 1, 1, 1, 1, 1, 1, 1],
    [0.990877, 0.915502, 1, 1.065173, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.736833, 0.993476, 1.04529, 0.971926, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.028973, 1.033754, 1.038338, 1.042735, 1.046966, 1, 1],
    [1.15639, 0.408838, 1, 1.61666, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 0.9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.992291, 0.993556, 1, 1.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.00367, 1, 1, 1.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.302576, 1, 1.066638, 1, 1, 1, 1.028973, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.191904, 1, 1.077634, 1, 1, 1, 1.033754, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.205769, 1, 1.088178, 1, 1, 1, 1.038338, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.219634, 1, 1.098291, 1, 1, 1, 1.042735, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.233498, 1, 1.108021, 1, 1, 1, 1.046966, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

  UIJ = transpose(UIJ)

  // 给KIJ赋初值
  let KIJ = [[1, 1.00363, 0.995933, 1, 1.007619, 1, 1.00008, 1.02326, 1, 1, 1, 0.997596, 1, 1.002529, 0.982962, 0.983565, 0.982707, 0.981849, 0.980991, 1, 1],
    [1.00363, 1, 0.982361, 1.00796, 1, 1, 0.942596, 1.03227, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.995933, 0.982361, 1, 1.00851, 1, 1, 1.00779, 1, 1, 1, 1, 1, 1, 1, 0.910183, 0.895362, 0.881152, 0.86752, 0.854406, 1, 1],
    [1, 1.00796, 1.00851, 1, 0.986893, 1, 0.999969, 1.02034, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.007619, 1, 1, 0.986893, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.00008, 0.942596, 1.00779, 0.999969, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.96813, 0.96287, 0.957828, 0.952441, 0.948338, 1, 1],
    [1.02326, 1.03227, 1, 1.02034, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.997596, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.002529, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.982962, 1, 0.910183, 1, 1, 1, 0.96813, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.983565, 1, 0.895362, 1, 1, 1, 0.96287, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.982707, 1, 0.881152, 1, 1, 1, 0.957828, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.981849, 1, 0.86752, 1, 1, 1, 0.952441, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.980991, 1, 0.854406, 1, 1, 1, 0.948338, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

  KIJ = transpose(KIJ)

  // 给GIJ赋初值
  let GIJ = [[1, 1, 0.807653, 1, 1, 1, 1, 1.95731, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 0.982746, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0.807653, 0.982746, 1, 0.370296, 1, 1.67309, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 0.370296, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1.67309, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1.95731, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

  GIJ = transpose(GIJ)

  //******************************************************************************************************************
  // 摩尔分数标准化
  let XI = p_compo_arr
  XI = [0].concat(XI)
  // 计算平均摩尔质量
  let MWX = 摩尔质量_燃气(组分体积分数数组)
  // ***************************************************计算第二维里系数*************************************************
  let BI = new Array(19)
  let K1 = 0
  let U1 = 0
  let G1 = 0
  let Q1 = 0
  let F1 = 0
  let E1 = 0
  for (let i = 1; i < 22; i++) {
    K1 = K1 + XI[i] * Math.pow(KI[i], 2.5)
    U1 = U1 + XI[i] * Math.pow(EI[i], 2.5)
    G1 = G1 + XI[i] * GI[i]
    Q1 = Q1 + XI[i] * QI[i]
    F1 = F1 + XI[i] * XI[i] * FI[i]
    E1 = E1 + XI[i] * EI[i]
  }

  // '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  let TCM = 1.261 * E1
  let DCM = Math.pow(K1, -1.2)
  K1 = K1 * K1
  U1 = U1 * U1
  for (let i = 1; i < 21; i++) {
    for (let j = i + 1; j < 22; j++) {
      let XIJ = XI[i] * XI[j]
      if (XIJ !== 0) {
        K1 = K1 + 2 * XIJ * (Math.pow(KIJ[i - 1][j - 1], 5) - 1) * Math.pow(KI[i] * KI[j], 2.5)
        U1 = U1 + 2 * XIJ * (Math.pow(UIJ[i - 1][j - 1], 5) - 1) * Math.pow(EI[i] * EI[j], 2.5)
        G1 = G1 + XIJ * (GIJ[i - 1][j - 1] - 1) * (GI[i] + GI[j])
      }
    }
  }

  K1 = Math.pow(K1, 0.2)
  U1 = Math.pow(U1, 0.2)

  // '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  for (let n = 1; n <= 18; n++) {
    let BBN = 0
    for (let i = 1; i <= 21; i++) {
      for (let j = 1; j <= 21; j++) {
        let XIJ = XI[i] * XI[j]
        let EIJ0 = EIJ[i - 1][j - 1] * Math.pow((EI[i] * EI[j]), 0.5)
        let GIJ0 = GIJ[i - 1][j - 1] * (GI[i] + GI[j]) / 2

        let BN = Math.pow(GIJ0 + 1 - G[n], (G[n]))
          * Math.pow(QI[i] * QI[j] + 1 - Q[n], Q[n])
          * Math.pow(Math.pow(FI[i], 0.5) * Math.pow(FI[j], 0.5) + 1 - F[n], F[n])
          * Math.pow(SI[i] * SI[j] + 1 - S[n], S[n])
          * Math.pow(WI[i] * WI[j] + 1 - W[n], W[n])

        BBN = BBN + XIJ * Math.pow(EIJ0, U[n]) * Math.pow(KI[i] * KI[j], 1.5) * BN
      }
    }
    BI[n] = a[n] * BBN
  }

  let CNS = []
  // ************************************************求解系数CN********************************************************
  for (let n = 13; n <= 58; n++) {
    CNS[n] = Math.pow(G1 + 1 - G[n], G[n]) * Math.pow((Math.pow(Q1, 2) + 1 - Q[n]), Q[n])
      * Math.pow((F1 + 1 - F[n]), F[n]) * a[n] * Math.pow(U1, U[n])
  }
  // *********************************************开始循环求解**********************************************************

  // Dim D_unknown, Z, BMIX As Double
  let TOL = 0.5 * Math.pow(10, -9)
  let X1 = 0.000001
  let X2 = 40
  let D_unknown = 0
  let Z
  let temp = PZOFDT(X1, 温度, B, BI, C, CNS, K, K1, U)
  let FF1 = temp['P']
  temp = PZOFDT(X2, 温度, B, BI, C, CNS, K, K1, U)
  let FF2 = temp['P']

  FF1 = FF1 - 压力
  FF2 = FF2 - 压力

  if (FF1 * FF2 >= 0) {
    return
  }

  // '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  for (let I = 1; I <= 5000; I++) {
    D_unknown = (X1 + X2) / 2
    temp = PZOFDT(D_unknown, 温度, B, BI, C, CNS, K, K1, U)
    let FF = temp['P']
    Z = temp['Z']
    FF = FF - 压力

    if (Math.abs(FF) < TOL) {
      break
    }
    if (FF * FF1 < 0) {
      X2 = D_unknown
    } else {
      X1 = D_unknown
    }


  }
  return Z

}

function PZOFDT(D, T, B, BI, C, CNS, K, K1, U) {
  if (T < 230) {  // 如果燃气温度小于230，则说明单位是摄氏度，这里转为开尔文温度
    T = T + 273.15
  }
  let DR = D * Math.pow(K1, 3)
  let P
  let Z
  let BMIX = 0
  for (let n = 1; n <= 18; n++) {
    BMIX = BMIX + BI[n] / Math.pow(T, U[n])
  }

  Z = 1 + BMIX * D

  for (let n = 13; n <= 18; n++) {
    Z = Z - DR * CNS[n] / Math.pow(T, U[n])
  }

  for (let n = 13; n <= 58; n++) {
    Z = Z + CNS[n] / Math.pow(T, U[n]) * (B[n] - C[n] * K[n] * Math.pow(DR, K[n])) * Math.pow(DR, B[n]) * Math.exp(-C[n] * Math.pow(DR, K[n]))
  }
  P = D * R * T * Z
  return { P, Z }  // 返回的P迭代中间压力，Z是迭代终止时的压缩因子
}

function 密度_燃气(压力, 温度, 组分体积分数数组) {
  let z_gas = 压缩因子(压力, 温度, 组分体积分数数组)
  let rho_mole = 压力 / z_gas / 0.00831451 / (温度 + 273.15)
  let mass_mole = 摩尔质量_燃气(组分体积分数数组)
  return rho_mole * mass_mole
}

function transpose(matrix) {
  let result = new Array(matrix.length).fill(0).map(arr => new Array(matrix[0].length).fill(0))
  for (let i = 0; i < result.length; i++) {
    for (let j = 0; j < result[0].length; j++) {
      result[i][j] = matrix[j][i]
    }
  }
  return result
}


/**
 * 线性插值函数 - VBA xz 函数的JavaScript版本
 * @param {number} x - 要插值的点
 * @param {Array|Object} X_list - X坐标数组
 * @param {Array|Object} Y_list - Y坐标数组
 * @returns {number} 插值结果
 */
function xz(x, X_list, Y_list) {
  // 处理Excel对象的情况
  let xArray, yArray

  // 如果X是Excel对象，提取值
  xArray = array_from_region(X_list)

  yArray = array_from_region(Y_list)

  const n = xArray.length

  try {
    // 如果X数组是递增的
    if (xArray[0] < xArray[1]) {
      // 如果X1大于等于最大值，使用线性外推
      if (x >= xArray[n - 1]) {
        return (yArray[n - 1] - yArray[n - 2]) / (xArray[n - 1] - xArray[n - 2]) * (x - xArray[n - 1]) + yArray[n - 1]
      }

      // 如果X1小于等于最小值，使用线性外推
      if (x <= xArray[0]) {
        return (yArray[1] - yArray[0]) / (xArray[1] - xArray[0]) * (x - xArray[0]) + yArray[0]
      }

      // 在数组范围内进行线性插值
      for (let LP = 0; LP < n - 1; LP++) {
        if (x > xArray[LP] && x <= xArray[LP + 1]) {
          return (yArray[LP + 1] - yArray[LP]) / (xArray[LP + 1] - xArray[LP]) * (x - xArray[LP]) + yArray[LP]
        }
      }
    }
    // 如果X数组是递减的
    else if (xArray[0] > xArray[1]) {
      // 如果X1小于等于最小值，使用线性外推
      if (x <= xArray[n - 1]) {
        return (yArray[n - 1] - yArray[n - 2]) / (xArray[n - 1] - xArray[n - 2]) * (x - xArray[n - 1]) + yArray[n - 1]
      }

      // 如果X1大于等于最大值，使用线性外推
      if (x >= xArray[0]) {
        return (yArray[1] - yArray[0]) / (xArray[1] - xArray[0]) * (x - xArray[0]) + yArray[0]
      }

      // 在数组范围内进行线性插值
      for (let LP = 0; LP < n - 1; LP++) {
        if (x <= xArray[LP] && x >= xArray[LP + 1]) {
          return (yArray[LP + 1] - yArray[LP]) / (xArray[LP + 1] - xArray[LP]) * (x - xArray[LP]) + yArray[LP]
        }
      }
    }
  } catch (e) {
    // 忽略错误，返回undefined
  }

  // 如果没有匹配条件，返回undefined
  return undefined
}

function T_air_HX(焓, 含湿量) {
  // 根据湿空气比焓和含湿量计算空气干球温度，单位℃
  let a = 含湿量 * 2500
  let b = 焓 - a
  let c = 1.005 + 含湿量 * 1.846
  return b / c
}

/**
 * 计算空气中水的分压，需要注意传入的相对湿度单位是100，不是1
 * @param 相对湿度_100
 * @param 干球饱和压力_kPa
 * @returns {number}
 */
function 空气中水的分压(相对湿度_100, 干球饱和压力_kPa) {
  // 相对湿度, 0~100
  // 干球饱和压力，kPa
  if (相对湿度_100 > 1) {
    相对湿度_100 = 相对湿度_100 / 100
  }
  return 相对湿度_100 * 干球饱和压力_kPa
}

/**
 * 计算干空气分数，需要注意传入的相对湿度的单位为%，不是1
 *
 * @param 大气压力_kPa
 * @param 相对湿度_100
 * @param 干球饱和压力_kPa
 * @returns {number}
 */
function 干空气分数(大气压力_kPa, 相对湿度_100, 干球饱和压力_kPa) {
  // 大气压力，kPa
  // 相对湿度, 0~100
  // 干球饱和压力，kPa
  let p_water = 空气中水的分压(相对湿度_100, 干球饱和压力_kPa)
  return 1 - p_water / 大气压力_kPa
}

/**
 * 计算水蒸气饱和压力（kPa），ASME PTC 22燃气轮机性能试验规程，附录A-3.2.1.3
 * @param {number} 干球温度_C 摄氏温度
 * @returns {number|string} 饱和压力(kPa)；温度超出范围返回 null
 */
function 干球饱和压力_kPa(干球温度_C) {
  // 1. 温度转换
  const t_f = 干球温度_C * 1.8 + 32         // °F
  const T = t_f + 459.67                     // °R

  // 2. 选择系数
  let C
  if (干球温度_C >= -100 && 干球温度_C <= 0) {  // 冰面
    C = [
      -1.0214165e4,
      -4.8932428,
      -5.3765794e-3,
      1.9202377e-7,
      3.5575832e-10,
      -9.0344688e-14,
      4.1635019
    ]
  } else if (干球温度_C > 0 && 干球温度_C <= 200) {  // 水面
    C = [
      -1.0440397e4,
      -1.1294650e1,
      -2.7022355e-2,
      1.2890360e-5,
      -2.4780681e-9,
      0.0,
      6.5459673
    ]
  } else {
    return '温度超范围'
  }

  // 3. 计算 ln(P in psia)
  const lnP =
    C[0] / T +
    C[1] +
    C[2] * T +
    C[3] * T * T +
    C[4] * T * T * T +
    C[5] * T * T * T * T +
    C[6] * Math.log(T) // js中，log的底是e，不是10，log10的底才是10

  // 4. 由 psia → kPa
  const P_psia = Math.exp(lnP)
  return P_psia * 6.89476
}

function 摩尔分数_水(干空气分数) {
  return 1 - 干空气分数
}

function 摩尔分数_氮气(干空气分数) {
  return 0.780840 * 干空气分数
}

function 摩尔分数_氧气(干空气分数) {
  return 0.209476 * 干空气分数
}

function 摩尔分数_氩气(干空气分数) {
  return 0.009365 * 干空气分数
}

function 摩尔分数_二氧化碳(干空气分数) {
  return 0.000319 * 干空气分数
}

function 湿空气分子量(干空气分数) {
  return 28.01348 * 摩尔分数_氮气(干空气分数) + 31.9988 * 摩尔分数_氧气(干空气分数) + 44.0098 * 摩尔分数_二氧化碳(干空气分数)
    + 18.01528 * 摩尔分数_水(干空气分数) + 39.948 * 摩尔分数_氩气(干空气分数)
}

/**
 * 根据干空气分数计算含湿量，传入的干空气分数的单位是1，不是100
 * @param 压力_kPa
 * @param 干球温度_C
 * @param 相对湿度_100
 */
function 含湿量(压力_kPa, 干球温度_C, 相对湿度_100) {
  const 干空气分数_FDA_1 = 干空气分数(压力_kPa, 相对湿度_100, 干球饱和压力_kPa(干球温度_C))
  return 18.01528 * (1 / 干空气分数_FDA_1 - 1) / 28.9651159
}
